﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;


namespace TimeReporter
{
    public class myBindingListView<T> : BindingList<T>, IBindingList, IBindingListView
    {
        private bool m_Sorted = false;
        private bool m_Filtered = false;
        private string m_FilterString = null;
        private bool _isFilled = false;
        
        private ListSortDirection m_SortDirection = ListSortDirection.Ascending;
        private PropertyDescriptor m_SortProperty = null;
        private ListSortDescriptionCollection m_SortDescriptions = new ListSortDescriptionCollection();
        private List<T> m_OriginalCollection = new List<T>();
        public delegate void listIsFilled(object source);
        public event listIsFilled ListIsFilled;
        
        public myBindingListView() : base() { }

        public myBindingListView(List<T> list) : base(list) { }

        #region --------------- Definition of supported functions ---------------

        bool IBindingList.AllowNew
        {
            get
            {
                return CheckReadOnly();
            }
        }

        bool IBindingList.AllowRemove
        {
            get
            {
                return CheckReadOnly();
            }
        }

        bool IBindingListView.SupportsFiltering
        {
            get { return true; }
        }

        bool IBindingListView.SupportsAdvancedSorting
        {
            get { return false; }
        }

        private bool CheckReadOnly()
        {
            if (m_Sorted || m_Filtered)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        
        protected override bool SupportsSearchingCore
        {
            get
            {
                return true;
                
            }
        }

        protected override bool SupportsSortingCore
        {
            get { return true; }
        }

        #endregion

        public bool IsFilled
        {
            set
            {
                _isFilled = value;
                if (ListIsFilled != null)
                {
                    ListIsFilled(this);
                }
            }
            get { return _isFilled; }

        }

        #region --------------- Find support ---------------

        protected override int FindCore(PropertyDescriptor property, object key)
        {
            for (int i = 0; i < Count; i++)
            {
                T item = this[i];
                if (property.GetValue(item).Equals(key))
                {
                    return i;
                }
            }
            return -1; // Not found
        }

        #endregion

        #region --------------- Sort support ---------------

        protected override bool IsSortedCore
        {
            get { return m_Sorted; }
        }

        protected override ListSortDirection SortDirectionCore
        {
            get { return m_SortDirection; }
        }

        protected override PropertyDescriptor SortPropertyCore
        {
            get { return m_SortProperty; }
        }
        
        protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
        {
            m_SortDirection = direction;
            m_SortProperty = property;
            SortComparer<T> comparer = new
            SortComparer<T>(property, direction);
            ApplySortInternal(comparer);
        }

        private void ApplySortInternal(SortComparer<T> comparer)
        {
            // store the original order of the collection
            if (m_OriginalCollection.Count == 0)
            {
                m_OriginalCollection.AddRange(this);
            }

            List<T> listRef = this.Items as List<T>;
            if (listRef == null)
                return;

            // Let List<T> do the actual sorting based on your comparer
            listRef.Sort(comparer);
            m_Sorted = true;
            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

        ListSortDescriptionCollection IBindingListView.SortDescriptions
        {
            get { return m_SortDescriptions; }
        }
        
        void IBindingListView.ApplySort(ListSortDescriptionCollection sorts)
        {
            m_SortProperty = null;
            m_SortDescriptions = sorts;
            SortComparer<T> comparer = new SortComparer<T>(sorts);
            ApplySortInternal(comparer);
        }


        protected override void RemoveSortCore()
        {
            if (!m_Sorted)
                return;

            Clear();
            foreach (T item in m_OriginalCollection)
            {
                Add(item);
            }
            m_OriginalCollection.Clear();
            m_SortProperty = null;
            m_SortDescriptions = null;
            m_Sorted = false;
        }

        #endregion

        #region ----------- Filter support ----------------

        
        
        string IBindingListView.Filter
        {
            get
            {
                return m_FilterString;
            }
            set
            {
                m_FilterString = value;
                m_Filtered = true;
                UpdateFilter();
            }
        }



        protected virtual void UpdateFilter()
        {
            // "PropertyName > StartRange,PropertyName < EndRange" string filter

            string[] filterparts = m_FilterString.Split(',');

            int gtPos = filterparts[0].IndexOf('>');
            string startPropName = filterparts[0].Substring(0, gtPos).Trim();
            string startRange = filterparts[0].Substring(gtPos + 1, filterparts[0].Length - gtPos - 1).Trim();
            DateTime dtStartRange = DateTime.Parse(startRange);

            PropertyDescriptor propDescStartDate = TypeDescriptor.GetProperties(typeof(T))[startPropName];

            int ltPos = filterparts[1].IndexOf('<');
            string endPropName = filterparts[1].Substring(0, ltPos).Trim();
            string endRange = filterparts[1].Substring(ltPos + 1, filterparts[1].Length - ltPos - 1).Trim();
            DateTime dtEndRange = DateTime.Parse(endRange);

            PropertyDescriptor propDescEndDate = TypeDescriptor.GetProperties(typeof(T))[endPropName];
       
            if (m_OriginalCollection.Count == 0)
            {
                m_OriginalCollection.AddRange(this);
            }
            List<T> currentCollection = new List<T>(this);
            Clear();
            foreach (T item in currentCollection)
            {
                object startDate = propDescStartDate.GetValue(item);
                object endDate = propDescEndDate.GetValue(item);
                Console.WriteLine("Startdate: " + startDate.ToString());
                Console.WriteLine("Enddate: " + endDate.ToString());
                
                if ((DateTime)startDate >= dtStartRange && (DateTime)startDate <= dtEndRange)
                {
                    Add(item);
                    Console.WriteLine("Added");
                }
            }
        }



        void IBindingListView.RemoveFilter()
        {
            if (!m_Filtered)
                return;
            m_FilterString = null;
            m_Filtered = false;
            m_Sorted = false;
            //m_SortDescriptions = null;
            m_SortProperty = null;
            Clear();
            foreach (T item in m_OriginalCollection)
            {
                Add(item);
            }
            m_OriginalCollection.Clear();
        }

        #endregion
    }
}
